package sk.ygor.raynor.rebind.service

import com.google.gwt.core.ext.{GeneratorContext, TreeLogger, Generator}
import sk.ygor.raynor.rebind.serializable.JSONSerializableGenerator
import sk.ygor.xtemplate.XTemplate
import com.google.gwt.user.rebind.{SourceWriter, ClassSourceFileComposerFactory}
import com.google.gwt.user.client.rpc.AsyncCallback
import com.google.gwt.json.client.JSONValue
import sk.ygor.raynor.client.service.JSONService
import sk.ygor.raynor.client.json.JSONSerializer
import sk.ygor.raynor.rebind.common.ScalaGeneratorWorker

class JSONServiceGenerator extends Generator {
  def generate(logger: TreeLogger, context: GeneratorContext, inputClassName: String) =
    new ServiceGeneratorWorker(logger, context, inputClassName).generate
}

class ServiceGeneratorWorker(logger: TreeLogger, context: GeneratorContext, inputClassName: String)
        extends ScalaGeneratorWorker(logger, context, inputClassName) with JSONServiceAnalysis {
  def generateHeader(composer: ClassSourceFileComposerFactory) = {
    if (inputClassType.isInterface != null) {
      composer.addImplementedInterface(inputClassType.getParameterizedQualifiedSourceName())
    } else {
      composer.setSuperclass(inputClassType.getParameterizedQualifiedSourceName())
    }
    composer addImplementedInterface classOf[JSONService.Configuration]

    composer addImports (
            classOf[JSONValue],
            classOf[JSONService.Invoker],
            classOf[JSONService.Invoker.Parameter],
            classOf[JSONService.Configuration],
            classOf[JSONService.Transformer],
            classOf[JSONSerializer[_]],
            classOf[AsyncCallback[_]]
            )
  }

  def generateBody(sw: SourceWriter) = {
    val xtpl = new XTemplate("sk/ygor/raynor/rebind/service/JSONService.xtpl")
    for ((serviceMethod, methodIndex) <- analyzeServiceMethods(inputClassType).zipWithIndex) {
      xtpl.assign("methodName", serviceMethod.name)
      xtpl.assign("returnType", serviceMethod.returnType.getParameterizedQualifiedSourceName())
      xtpl.assign("servicePackageName", inputClassPackageName)
      xtpl.assign("serviceClassSimpleName", inputClassSimpleName)
      xtpl.assign("serviceMethodName", serviceMethod.name)
      xtpl.assign("resultDeserializerClassName", new JSONSerializableGenerator().generate(logger, context, serviceMethod.returnType))
      xtpl.assign("resultDeserializerInstance", "resultDeserializerInstance" + methodIndex)
      xtpl.parse("resultDeserializerInstance")
      xtpl.parse("resultDeserializerInstanceDelegateTransfomer")
      for (((parameterName, parameterType), parameterIndex) <- serviceMethod.parameterTypes.elements.zipWithIndex) {
        xtpl.assign("parameterName", parameterName)
        xtpl.assign("parameterType", parameterType.getParameterizedQualifiedSourceName())
        xtpl.assign("parameterSerializerClassName", new JSONSerializableGenerator().generate(logger, context, parameterType))
        xtpl.assign("parameterSerializerInstance", "parameterSerializerInstance" + methodIndex + "_" + parameterIndex)
        xtpl.parse("parameterSerializerInstance")
        xtpl.parse("parameterSerializerInstanceDelegateTransfomer")
        xtpl.parse("method.parameter")
        xtpl.parse("method.serializedParameter")
      }
      xtpl.parse("method")
    }
    xtpl.parse()
    sw.println(xtpl.getText())
  }


}
